package Day_0131.JVM;

/**
 * @author zxc
 * @date 2023/01/31 17:09
 **/
public class JVM_MemoryModel {
    public static void main(String[] args) {
        /**
         * JVM内存模型
         *
         * 1、JVM内存模型：
         * （1）线程独占: 栈,本地方法栈,程序计数器;（专属于每个线程）
         * （2）线程共享:堆,方法区（单个进程中每个线程所共享的;）
         *
         * 2、栈：（虚拟机栈）
         * （1）线程私有的,线程执行方法是都会创建一个栈阵,用来存储局部变量表,操作栈,动态链接,方法出口等信息.
         * （2）调用方法时执行入栈,方法返回式执行出栈.
         *
         * 3、本地方法栈
         * 与栈类似,也是用来保存执行方法的信息.
         * 执行Java方法是使用栈,执行Native方法时使用本地方法栈.
         *
         * 4、程序计数器
         *  每个线程就需要一个属于自己的计数器来记录下一条要运行的指令。
         * （1）保存着当前线程执行的字节码位置,每个线程工作时都有独立的计数器,只为执行Java方法服务;
         * ===> 用于保存当前线程执行状态;
         * （线程进行上下文切换时，每个线程专属的程序计算器是用来恢复线程执行状态的）
         * （2）执行Native方法时,程序计数器为空.
         *
         * 5、堆（Heap）
         *  存放对象实例和数组，是垃圾回收的主要区域;
         * （1）JVM内存管理最大的一块,对被所有线程共享;
         * （2）目的是存放对象的实例,几乎所欲的对象实例都会放在这里,当堆没有可用空间时,会抛出OOM异常.
         * （3）根据对象的存活周期不同,JVM把对象进行分代管理,由垃圾回收器进行垃圾的回收管理;
         * ===》 年轻代 - 老年代 - 永久代（分代管理后，所使用的垃圾回收算法是不一样的;）
         *
         * 6、方法区：
         *  线程共享的，用于存放被虚拟机加载的类的元数据信息;
         * （1）用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器优化后的代码等数据;
         * （2）1.7的永久代和1.8的元空间都是方法区的一种实现;
         *
         * 如果hotspot虚拟机确定一个类的定义信息不会被使用，也会将其回收。
         * ===》
         * （1）所有该类的实例被回收;
         * （2）装载该类的ClassLoader被回收;
         *
         * 7.JVM内存可见性
         * （1）JMM是定义程序中变量的访问规则,线程对于变量的操作只能在自己的工作内存中进行,而不能直接对主内存操作;
         * ===》 即，每个线程都有专属的工作内存;
         * （主内存中共享变量拷贝到每个线程的工作内存中进行处理后，刷新会主内存;）
         * （2）由于指令重排序,读写的顺序会被打乱,因此JMM需要提供原子性,可见性,有序性保证.
         */

        /**
         * 类加载过程 ：
         * （Class文件，即字节码文件，加载为Class对象;）
         * 其中验证,准备,解析合称链接
         * 1.加载 ：
         * 加载通过 类的完全限定名 ,查找此类字节码文件,利用字节码文件创建Class对象.
         *
         * 2.链接
         * （1）验证
         * 验证确保Class文件符合当前虚拟机的要求,不会危害到虚拟机自身安全.
         *
         * （2）准备
         * 准备进行内存分配,为static修饰的类变量分配内存,并设置初始值(0或null).不包含final修饰的静态变量,因为final变量在编译时分配.
         *
         * （3）解析
         * 解析将常量池中的符号引用替换为直接引用的过程.直接引用为直接指向目标的指针或者相对偏移量等.
         *
         * 3.初始化
         * 初始化主要完成静态块执行以及静态变量的赋值.先初始化父类,再初始化当前类.
         * 对类主动使用时才会初始化;
         * ===>
         * 初始化的触发条件 ：
         * （1）创建类的实例时;
         * （2）访问类的静态方法或静态变量的时候;
         * （3）使用Class.forName反射类的时候;
         * （4）或者某个子类初始化的时候;
         *
         * 注意 ：Java自带的加载器加载的类,在虚拟机的生命周期中是不会被卸载的,只有用户自定义的加载器加载的类才可以被卸载;
         *
         * 1、加载机制-双亲委派模式
         *
         * 双亲委派模式,即加载器加载类时先把请求委托给自己的父类加载器执行,直到顶层的启动类加载器;
         * ===》 即，自底向上委托请求;
         * 父类加载器能够完成加载则成功返回,不能则子类加载器才自己尝试加载;
         * ===》 即，自顶向下进行加载;
         *
         * 类加载器的优先级顺序 ：BootStrap根加载器 > EXTension扩展类加载器 > Application类加载器 > 自定义加载器
         *
         * 注意 ：用户自定义类加载器，即实现java.lang.ClassLoader（也就是其java.lang.ClassLoader的子类;）
         *
         * 优点:
         * （1） 避免类的重复加载
         * （2）避免Java的核心API被篡改
         *
         */

        /**
         * 分代回收 ：
         * 年轻代 ：标记-复制;
         * 老年代 ：标记-清除;
         *
         * （1）年轻代 ：Eden区,Survivor1区,Survivor2区;
         *  ===》 年轻代中对象，为较新创建的对象;
         *  （轻GC，所清理的就是年轻代中的对象;）
         *
         * （2）老年代 : （重GC，所清理的就是老年代中的对象 && 年轻代中的对象）;
         *
         * （3）永久代 ：即，存储在方法区中的对象;
         *  ===> 注意 ：方法区在jdk1.8之前的实现为永久代（在JVM虚拟机堆内存中）;在jdk1.8之后的实现为元空间（在本地内存中）;
         *
         */
    }
}
